C++ 与 lua 联合编程

| 2024-09-02 10:20:38

环境部署

有两种方案

全局安装 lua 解释器

brew install lua

使用 pkg-config 在 cmake 中载入 lua

find_package(PkgConfig REQUIRED)
pkg_check_modules(LUA REQUIRED lua)
target_link_libraries(main PRIVATE ${LUA_LIBRARIES})
target_link_directories(main PRIVATE ${LUA_LIBRARY_DIRS})
target_include_directories(main PRIVATE ${LUA_INCLUDE_DIRS})

vcpkg

{
    "name":             "cxx-lua",
    "version-string":   "1.0.0",
    "builtin-baseline": "e590c2b30c08caf1dd8d612ec602a003f9784b7d",
    "dependencies":     [
        {
            "name":      "lua",
            "version>=": "5.4.6"
        }
    ]
}

在 cmake 中载入 lua

find_package(Lua REQUIRED)
target_include_directories(main PRIVATE ${LUA_INCLUDE_DIR})
target_link_libraries(main PRIVATE ${LUA_LIBRARIES})

vcpkg 也支持全局模式,与 brew 用法区别不大不再赘述

Hello World

为了避免函数名冲突,要使用 extern “C” 包裹lua头文件,声明这些是C的函数。 lua 是脚本语言,修改 lua 文件之后无需重新编译 C++,重新执行程序即可

main.lua

print "Hello World"

main.cpp

#include <iostream>

// 避免函数签名冲突
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}

int main() {
    lua_State* L = luaL_newstate(); // 5.0 之后使用 luaL_newstate 替代 lua_open
    if (!L) {
        std::cerr << "Cannot create state: Not enough memory" << std::endl;
        return 1;
    }

    luaL_openlibs(L);

    if (luaL_loadfile(L, "main.lua")) {
        std::cerr << "lua load error: " << lua_tostring(L, -1) << std::endl;
    }

    if (lua_pcall(L, 0, 0, 0)) {
        std::cerr << "lua call error: " << lua_tostring(L, -1) << std::endl;
    }

    lua_close(L);
    return 0;
}

执行结果

Hello World

变量

全局变量,全局可用

a = 100

本地变量,从当前作用域离开之后就会被垃圾回收,类似 RAII

local a = 100 

数据类型

四个基础数据类型

Booleans 和 Nil 不赘述

识别变量类型

i = 100
s = "str"
print(type(i), type(s))

运行结果

number  string

Numbers

在 lua 5.1 之后 int 类型基于双精度类型存储

a = 100

Strings

a = "string"

多行字符串使用 [[]] 定义

s = [[
<html>
    <h1>Hello World
    </h1>
</html>
]]

print(s)

拼接字符串使用 .. 运算符,同时也可以拼接数字类型

a = "lua".."str"..123

一部分标准库

类型转换

i = 100
s = "1"

print(type(i), type(s))
print(type(tostring(i)), type(tonumber(s)))

运行结果

number  string
string  number

数组

在 lua 中引用其他 lua 文件

dofile("do.lua")

示例程序

main.lua

a = 100
local b = 1

print("print a in main.lua", a)
print("print b in main.lua", b)

dofile("sub.lua")

sub.lua

print("print a in sub.lua", a)
print("print b in sub.lua", b)

执行结果

全局变量可以跨文件读取,但局部变量不能

print a in main.lua     100
print b in main.lua     1
print a in sub.lua      100
print b in sub.lua      nil

流程控制

分支

分支采用 if then end 结构,elseif 也要加 then

a = 2;

if (a == 1 or a == 2) then
	print(12, a)
elseif (a == 3) then
	print(3, a)
else
	print(0, a)
end

循环

while

a = 0;

while (a < 5) do
    print(a)
    a = a + 1
end

运行结果

0
1
2
3
4

repeat

repeat .. until 类似 do .. while

a = 0;

repeat
    print(a)
    a = a + 1
until a > 5

for

for 

泛型